﻿using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Web;
using AK.Wwise;
using UnityEngine;
using Yoozoo.Gta.Common;
using Yoozoo.Libs;
using Yoozoo.Managers;
using Yoozoo.Mars.Got.SpriteAnim;
using Object = System.Object;

namespace Yoozoo.Modules.InnerCity
{
    public class CityUnitAction : IClass
    {
        public StateAction action;

        public object arg;

        public void OnReset()
        {
            this.action = StateAction.None;
            this.arg = null;
        }
    }

    public class CityUnit : IClass
    {
        private AnimSprite display;
        
        private CityUnitData initTransformData;
        
        private int id;

        private string type;

        private StateMachine stateController;
        
        private List<Vector3> moveWayPoints;

        // 当前归属的建筑队
        private CityBuildingTeam buildTeam;

        // 单位每次移动是做什么的
        private StateAction moveEndAction;

        // 去取的资源是什么
        private int takeObjType;
        
        // 是否停止行动
        private bool isStopMove;

        public int ID
        {
            get => this.id;
        }

        public Vector3 Position
        {
            get => this.display.position;
        }

        public Vector3 Rotation
        {
            get => this.display.rotation;
        }

        public float Scale
        {
            get => this.display.spriteSize / this.initTransformData.scale;
        }

        public StateAction CurState
        {
            get => this.stateController.CurState;
        }

        public bool IsBuilding
        {
            get => this.buildTeam != null;
        }

        public bool IsStopMove
        {
            get => this.isStopMove;
        }

        #region 状态机访问器

        public List<Vector3> MoveWayPoints
        {
            get => this.moveWayPoints;
        }

        public StateAction MoveEndAction
        {
            get => this.moveEndAction;
        }

        #endregion

        public void Initialize(int id, string type, AnimSprite sprite, List<string> actions, CityUnitData tranData)
        {
            // initialize render
            SetSprite(sprite);
            SetScale(tranData.scale);
            SetPosition(tranData.position);
            SetRotation(tranData.rotation);

            // initialize data
            this.id = id;
            this.type = type;
            
            // state machine
            InitStateMachine(actions);
            this.stateController.ChangeState(StateAction.Idle);
        }

        public void SetPosition(Vector3 position)
        {
            if (this.display == null)
                return;
            
            position.y += 0.5f * this.Scale;
            this.display.position = position;
        }

        public void SetPosition(float x, float y, float z)
        {
            if (this.display == null)
                return;

            var p = this.display.position;
            p.x = x;
            p.y = y + 0.5f * this.Scale;
            p.z = z;
            this.display.position = p;
        }

        public void SetRotation(Vector3 rotation)
        {
            if (this.display == null)
                return;

            this.display.rotation = rotation;
        }

        public void SetScale(float scale)
        {
            if (this.display == null)
                return;

            this.display.spriteSize = scale * this.initTransformData.scale;
        }

        public void SetSprite(AnimSprite sprite)
        {
            this.display = sprite;
            this.initTransformData = new CityUnitData(sprite.position, sprite.rotation, sprite.spriteSize);
        }


        public void Update()
        {
            this.stateController.Update();
        }

        // 建造入口
        public void WalkToBuild(List<Vector3> path, CityBuildingTeam parent)
        {
            this.stateController.ChangeState(StateAction.Idle);
            this.buildTeam = parent;
            Walk(path, StateAction.Build);
        }

        public void ReWalkToBuild(List<Vector3> path)
        {
            if (this.buildTeam == null)
                return;
            
            this.stateController.ChangeState(StateAction.Idle);
            Walk(path, StateAction.Build);
        }

        public void Build(CityBuildingTeam parent)
        {
            this.stateController.ChangeState(StateAction.Idle);
            this.buildTeam = parent;
            ChangeState(StateAction.Build);
        }
        
        public void Walk(List<Vector3> walkPath, StateAction walkToDo = StateAction.Idle)
        {
            var action = StateAction.Walk;
            if (!StateEnterCheck(action))
                return;

            this.moveEndAction = walkToDo;
            SetMoveWayPoints(walkPath);
            this.stateController.ChangeState(action);
        }

        public void ChangeState(StateAction stateAction, object arg = null)
        {
            if (!StateEnterCheck(stateAction))
                return;

            if (arg == null)
                arg = GetDefaultStateArg(stateAction);

            this.stateController.ChangeState(stateAction, arg);
        }

        public void ExecuteMoveEndAction()
        {
            ChangeState(this.moveEndAction);
            this.moveEndAction = StateAction.None;
        }

        // 行动
        public void PlayWalkAni()
        {
            if (this.display == null)
                return;
            
            CityUnitMgr.Instance.PlaySpriteAnimation(this.display, SPRITE_ACTION_ENUM.RUN);
        }

        // 静止
        public void PlayIdleAni()
        {
            if (this.display == null)
                return;
            
            CityUnitMgr.Instance.PlaySpriteAnimation(this.display, SPRITE_ACTION_ENUM.IDLE);
        }

        // 建造
        public void PlayBuildAni()
        {
            if (this.display == null)
                return;
            
            CityUnitMgr.Instance.PlaySpriteAnimation(this.display, SPRITE_ACTION_ENUM.ATTACK);
        }

        // 采集
        public void PlayCollectAni()
        {
            if (this.display == null)
                return;
            
            CityUnitMgr.Instance.PlaySpriteAnimation(this.display, SPRITE_ACTION_ENUM.IDLE);
        }

        // 扛东西
        public void PlayCarryAni()
        {
            if (this.display == null)
                return;

            Debug.Log(string.Format("扛着{0}移动", ResourceType.GetResourceName(this.takeObjType)));
            CityUnitMgr.Instance.PlaySpriteAnimation(this.display, SPRITE_ACTION_ENUM.RUN);
        }

        public void PlayCelebrateAni()
        {
            if (this.display == null)
                return;
            
            Debug.Log("我开始庆祝了");
            CityUnitMgr.Instance.PlaySpriteAnimation(this.display, SPRITE_ACTION_ENUM.IDLE);
        }

        public void SharePosToLua()
        {
            var callArg = ClassManager.Get<CallLuaArg>();
            callArg.code = CallLuaOperationCode.PersonArrivePoint;
            callArg.arg1 = this.id;
            callArg.arg2 = this.Position;
            CityUnitMgr.Instance.CallLuaWithoutResult(callArg);
        }

        public void CallNewRandomWalk()
        {
            var callArg = ClassManager.Get<CallLuaArg>();
            callArg.code = CallLuaOperationCode.PersonIdleEnd;
            callArg.arg1 = this.id;
            CityUnitMgr.Instance.CallLuaWithoutResult(callArg);
        }

        public void OnBuildEnd()
        {
            int type;
            Vector2Int targetGrid;
            var isBuild = this.buildTeam.IsBuildOrTakeObj();
            if (!isBuild && this.buildTeam.GetRandomResPoint(out type, out targetGrid))
            {
                var myGrid = CityUnitMgr.Instance.VectorToGrid(this.Position);
                var path = CityUnitMgr.Instance.FindPath(myGrid, targetGrid);
                if (path != null && path.Count > 0)
                {
                    this.takeObjType = type;
                
                    // 释放建筑占位
                    this.buildTeam.ExitBuildPos(this);
                    Walk(path, StateAction.Collect);
                }
                else
                    Walk(this.buildTeam.GetRandomBuildPosPath(this, myGrid), StateAction.Build);
            }
            else
                Walk(this.buildTeam.GetRandomBuildPosPath(this), StateAction.Build);
        }

        public void OnCollectEnd()
        {
            var action = StateAction.TakeObj;
            if (!StateEnterCheck(action))
                return;

            this.moveEndAction = StateAction.Build;
            SetMoveWayPoints(this.buildTeam.GetRandomBuildPosPath(this));
            this.stateController.ChangeState(action);
        }

        public void OnBuildTeamDismiss()
        {
            ChangeState(StateAction.Idle);
            this.buildTeam = null;
        }

        public void Celebrate()
        {
            ChangeState(StateAction.Celebrate);
        }

        public void Patrol(List<Vector3> path)
        {
            if (this.type != CityUnitType.Patrol)
                return;
            
            SetMoveWayPoints(path);
            ChangeState(StateAction.Patrol);
        }

        public void StopMove()
        {
            if (this.isStopMove)
                return;

            this.isStopMove = true;
            if (this.stateController.IsExecuteMove())
                PlayIdleAni();
        }

        public void ContinueMove()
        {
            if (!this.isStopMove)
                return;

            this.isStopMove = false;
            if (this.stateController.IsExecuteMove())
                PlayWalkAni();
        }

        public void OnReset()
        {
            Dispose();
        }

        // 检测是否可以进入
        private bool StateEnterCheck(StateAction state)
        {
            return true;
        }

        private void SetMoveWayPoints(List<Vector3> wayPoints, bool isReplace = true)
        {
            if (wayPoints == null || wayPoints.Count == 0)
                return;

            if (isReplace)
                this.moveWayPoints = wayPoints;
            else
                this.moveWayPoints.AddRange(wayPoints);
        }

        private object GetDefaultStateArg(StateAction state)
        {
            switch (state)
            {
                case StateAction.Idle:
                    return 5.0f;
                
                case StateAction.Walk:
                    return null;
                
                case StateAction.Build:
                    if (this.buildTeam != null)
                        return this.buildTeam.GetRandomBuildTime();
                    else
                        return 2.0f;
                
                case StateAction.Collect:
                    if (this.buildTeam != null)
                        return this.buildTeam.GetRandomCollectTime();
                    else
                        return 4.0f;
                
                case StateAction.Celebrate:
                    return 3.0f;

                default:
                    return null;
            }
        }
        
        private void InitStateMachine(List<string> actions)
        {
            this.stateController = ClassManager.Get<StateMachine>();
            this.stateController.Initialize(this, actions);
        }

        private void Dispose()
        {
            CityUnitMgr.Instance.RemoveSprite(this.display);
            this.initTransformData = null;
            this.id = 0;
            ClassManager.Free(this.stateController);
            this.moveWayPoints = null;
            this.buildTeam = null;
            this.moveEndAction = StateAction.None;
            this.takeObjType = ResourceType.None;
        }
    }
}